
/**
  ******************************************************************************
  * Copyright 2021 The grapilot Authors. All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  * 
  * http://www.apache.org/licenses/LICENSE-2.0
  * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * 
  * @file       notify_rgb_led.h
  * @author     baiyang
  * @date       2022-1-16
  ******************************************************************************
  */

#pragma once

#ifdef __cplusplus
extern "C"{
#endif

/*----------------------------------include-----------------------------------*/
#include "notify_device.h"
/*-----------------------------------macro------------------------------------*/
#define DEFINE_COLOUR_SEQUENCE(S0, S1, S2, S3, S4, S5, S6, S7, S8, S9)  \
    ((S0) << (0*3) | (S1) << (1*3) | (S2) << (2*3) | (S3) << (3*3) | (S4) << (4*3) | (S5) << (5*3) | (S6) << (6*3) | (S7) << (7*3) | (S8) << (8*3) | (S9) << (9*3))

#define RGB_BLACK  0
#define RGB_BLUE   1
#define RGB_GREEN  2
#define RGB_RED    4
#define RGB_YELLOW (RGB_RED|RGB_GREEN)
#define RGB_WHITE (RGB_RED|RGB_GREEN|RGB_BLUE)

#define DEFINE_COLOUR_SEQUENCE_SLOW(colour)                       \
    DEFINE_COLOUR_SEQUENCE(colour,colour,colour,colour,colour,RGB_BLACK,RGB_BLACK,RGB_BLACK,RGB_BLACK,RGB_BLACK)
#define DEFINE_COLOUR_SEQUENCE_FAILSAFE(colour) \
    DEFINE_COLOUR_SEQUENCE(RGB_YELLOW,RGB_YELLOW,RGB_YELLOW,RGB_YELLOW,RGB_YELLOW,colour,colour,colour,colour,colour)
#define DEFINE_COLOUR_SEQUENCE_SOLID(colour) \
    DEFINE_COLOUR_SEQUENCE(colour,colour,colour,colour,colour,colour,colour,colour,colour,colour)
#define DEFINE_COLOUR_SEQUENCE_ALTERNATE(colour1, colour2)                      \
    DEFINE_COLOUR_SEQUENCE(colour1,colour2,colour1,colour2,colour1,colour2,colour1,colour2,colour1,colour2)
/*----------------------------------typedef-----------------------------------*/
typedef struct rgb_led* rgb_led_t;
typedef struct rgb_led_ops* rgb_led_ops_t;

enum rgb_source_t {
    rgb_standard = 0,
    rgb_mavlink = 1,
    rgb_obc = 2,
    rgb_traffic_light = 3,
};

/** @ 
  * @brief  
  */
struct rgb_led_ops {
    // set_rgb - set color as a combination of red, green and blue levels from 0 ~ 15
    void (*set_rgb)(rgb_led_t rgb_dev, uint8_t red, uint8_t green, uint8_t blue);

    // methods implemented in hardware specific classes
    bool (*hw_set_rgb)(rgb_led_t rgb_dev, uint8_t red, uint8_t green, uint8_t blue);

    // set_rgb - set color as a combination of red, green and blue levels from 0 ~ 15
    void (*_set_rgb)(rgb_led_t rgb_dev, uint8_t red, uint8_t green, uint8_t blue);
};

struct rgb_led {
    // 
    struct notify_device notify_dev;

    rgb_led_ops_t ops;

    // meta-data common to all hw devices
    uint8_t _red_curr, _green_curr, _blue_curr;  // current colours displayed by the led
    uint8_t _led_off;
    uint8_t _led_bright;
    uint8_t _led_medium;
    uint8_t _led_dim;

    struct {
        uint8_t r, g, b;
        uint8_t rate_hz;
        uint32_t start_ms;
    } _led_override;

    uint8_t last_step;
};

/*----------------------------------variable----------------------------------*/

/*-------------------------------------os-------------------------------------*/

/*----------------------------------function----------------------------------*/
void rgb_led_ctor(rgb_led_t led, uint8_t led_off, uint8_t led_bright, uint8_t led_medium, uint8_t led_dim);
struct rgb_led_ops rgb_led_ops();
struct notify_device_ops rgb_led_notify_device_ops();
enum rgb_source_t rgb_led_rgb_source(rgb_led_t led);
uint8_t rgb_led_get_brightness(rgb_led_t led);
uint32_t rgb_led_get_colour_sequence_obc();
uint32_t rgb_led_get_colour_sequence();
void rgb_led_update_override(rgb_led_t led);


static inline bool rgb_led_hw_set_rgb(rgb_led_t led, uint8_t red, uint8_t green, uint8_t blue) {
    RT_ASSERT(led != RT_NULL);
    RT_ASSERT(led->ops->hw_set_rgb != RT_NULL);

    return led->ops->hw_set_rgb(led, red, green, blue);
}

static inline void rgb_led_set_rgb(rgb_led_t led, uint8_t red, uint8_t green, uint8_t blue) {
    if (led->ops->set_rgb) {
         led->ops->set_rgb(led, red, green, blue);
    }
}

static inline void rgb_led_set_rgb2(rgb_led_t led, uint8_t red, uint8_t green, uint8_t blue) {
    if (led->ops->_set_rgb) {
         led->ops->_set_rgb(led, red, green, blue);
    }
}

static inline void rgb_led_update(rgb_led_t led) {
    notify_device_update(&led->notify_dev);
}

/*------------------------------------test------------------------------------*/

#ifdef __cplusplus
}
#endif



